// Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::Context;
use clap::Parser;

use crate::{build::BuildContext, commands::BuildGraphArgsRef, database::local::PKGS_ROOT, utils::sha256_to_string, FerriumCommand};

#[derive(Debug, Parser)]
pub struct ShowHashCommand {
    /// Pkg spec strings or specs config paths
    #[arg(long)]
    extra_specs: Option<Vec<String>>,
    /// Specify the toolchain to use
    #[arg(long)]
    toolchain: Option<String>,
    /// The output will be the path to pkg
    #[arg(short, long, group = "output_mode")]
    path: bool,
    /// The output will be the hash spec string of pkg
    #[arg(long, group = "output_mode")]
    hash_spec: bool,
    /// The output will be the hash string of pkg, default output mode
    #[arg(long, group = "output_mode", default_value_t = true)]
    hash: bool,
    /// The input pkg spec string
    spec: String,
}

impl FerriumCommand for ShowHashCommand {
    async fn run(self, _multi_progress: indicatif::MultiProgress) -> anyhow::Result<()> {
        let (mut dep_graph, _, _) = BuildGraphArgsRef {
            specs: [self.spec.as_str()].into_iter()
                .chain(self.extra_specs.unwrap_or_default().iter().map(|s| s.as_str())),
            toolchain: self.toolchain,
        }.build_graph().await?;
        let sorted_ids = dep_graph.verify(true)
            .context("failed to resolve specs")?;

        let hashes = BuildContext::spec_hashes(&dep_graph, &sorted_ids).await?;
        let spec_id = dep_graph.id_map.specs().next().unwrap();
        let sha256 = hashes[spec_id.index()];
        if self.path {
            let node = dep_graph.node(spec_id).unwrap();
            println!("{}", PKGS_ROOT.join(BuildContext::unique_spec_string(&sha256, &node.spec.pkg, node.spec.arch)).display());
        } else if self.hash_spec {
            let node = dep_graph.node(spec_id).unwrap();
            println!("{}", BuildContext::unique_spec_string(&sha256, &node.spec.pkg, node.spec.arch));
        } else if self.hash {
            println!("{}", sha256_to_string(&sha256));
        }

        Ok(())
    }
}
